package com.apes.fn.business.fixedLoss.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.fn.business.fixedLoss.modle.LossQuotation;
import com.apes.fn.business.fixedLoss.modle.LossReceivedApportion;
import com.apes.fn.business.fixedLoss.modle.LossReceivedItem;
import com.apes.fn.business.fixedLoss.repository.LossReceivedApportionRepository;
import com.apes.fn.business.fixedLoss.repository.LossReceivedItemRepository;
import com.apes.fn.scm.lossSale.LossSaleAdjust;
import com.apes.fn.scm.retailOrder.model.RetailOrderPayMethod;
import com.apes.fn.scm.retailOrder.repository.RetailOrderRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.DateUtil;
import com.apes.scm.masterdata.enumeration.model.Enumeration;
import com.apes.scm.masterdata.frame.model.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @program: apes-server
 * @description:
 * @author: czs
 * @create: 2022-09-29 15:45
 **/
@Service("lossReceivedApportionService")
public class LossReceivedApportionService extends DomainService {

    @Autowired
    private LossReceivedApportionRepository lossReceivedApportionRepository;
    @Autowired
    private RetailOrderRepository retailOrderRepository;

    public LossReceivedApportion create(LossReceivedApportion lossReceivedApportion){
        lossReceivedApportionRepository.saveAndFlush(lossReceivedApportion);
        //创建待缴款单
        createToPrepare(lossReceivedApportion);
        return lossReceivedApportion;
    }

    public LossReceivedApportion save(LossReceivedApportion lossReceivedApportion){
        lossReceivedApportionRepository.saveAndFlush(lossReceivedApportion);
        return lossReceivedApportion;
    }

    /**
     * 查询所有分摊中和分摊完的
     *
     * @param lossQuotation
     * @return -resultJson.apportionComplete:分摊完成
     * -resultJson.unappropriated:未分摊
     */
    public JSONObject findAllApportionOrder(LossQuotation lossQuotation) {

        JSONObject resultJson = new JSONObject();

        List<String> apportionComplete = lossReceivedApportionRepository.findAll(JpaDsl.toCriteria(
                "lossQuotationId", "EQ", lossQuotation.getId(),
                "unappropriatedAmount", "EQ", 0)
        ).stream().map(LossReceivedApportion::getApportionOrder).collect(Collectors.toList());
        List<Map> collect = lossReceivedApportionRepository.findAll(JpaDsl.toCriteria(
                "lossQuotationId", "EQ", lossQuotation.getId(),
                "unappropriatedAmount", "GT", 0)
        ).stream().map(this::getUnappropriatedMapper)
                .collect(Collectors.toList());

        resultJson.put("apportionComplete", apportionComplete);
        resultJson.put("unappropriated", collect);

        return resultJson;

    }

    private Map getUnappropriatedMapper(LossReceivedApportion item) {
        return mapper(
                "id", item.getApportionOrder(), "type", item.getApportionOrderType(),
                "source",item.getType(),
                "date",item.getReceivedDate(),"privateAmount",item.getPrivateAccountAmount(),
                "amount", item.getUnappropriatedAmount()-item.getPrivateAccountAmount(),"apportionId",item.getId());
    }

    /**
     *
     * 分摊未完成
     *
     * @param item 到账明细
     * @param unappropriated 待分摊明细
     */
    public void unappropriatedToComplete(LossReceivedItem item, List<Map> unappropriated) {
        if (unappropriated == null || unappropriated.size() == 0 || item.isApportionComplete()) return;
        for (int i = 0; i < unappropriated.size(); i++) {
            Map map = unappropriated.get(i);
            //可分摊金额
            double waitAppropriatedAmount = item.getReceivedAmount() - item.getApportionAmount();
            if (waitAppropriatedAmount<=0)return;
            Double amount = 0.0D;
            Double otherAmount = 0.0D;
            //门店私户摊现金
            if (item.getAccountType().getId().equals("002033")){
                amount = (Double) map.get("privateAmount");
                otherAmount = (Double) map.get("amount");
            }else {
                amount = (Double) map.get("amount");
                otherAmount = (Double) map.get("privateAmount");
            }
            if (amount<=0)continue;
            LossReceivedApportion lossReceivedApportion = new LossReceivedApportion();
            lossReceivedApportion.setApportionOrder((String) map.get("id"));
            lossReceivedApportion.setApportionOrderType((String) map.get("type"));
            lossReceivedApportion.setReceivedDate((Date) map.get("date"));
            //未分摊金额-可分摊金额 >0则未到账 <0则全部到账
            double unappropriatedAmount = amount+otherAmount - waitAppropriatedAmount;
            //分摊完标记 true 不可 false 可
            boolean receivedFlag = unappropriatedAmount >= 0;
            lossReceivedApportion.setUnappropriatedAmount(receivedFlag ? unappropriatedAmount : 0);
            lossReceivedApportion.setApportionAmount(amount+otherAmount - lossReceivedApportion.getUnappropriatedAmount());
            lossReceivedApportion.setNeedApportionAmount(amount+otherAmount);
            lossReceivedApportion.setLossQuotationId(item.getLossQuotation().getId());
            lossReceivedApportion.setLossReceivedItem(item);
            amount-=lossReceivedApportion.getApportionAmount();
            //找到原先未分摊完成的改为分摊完成
            updateResoure(map);
            if (map.get("apportionsType")!=null&&!map.get("apportionsType").equals("RO"))lossReceivedApportion.setType("RT");
            //清除待分摊记录
            if (item.getAccountType().getId().equals("002033")){
                map.put("privateAmount",amount);
                map.put("amount",otherAmount);
                lossReceivedApportion.setPrivateAccountAmount(amount);
            }else {
                lossReceivedApportion.setPrivateAccountAmount(otherAmount);
                map.put("privateAmount",otherAmount);
                map.put("amount",amount);
            }
            lossReceivedApportion = create(lossReceivedApportion);
            unappropriated.remove(i);
            if (amount>0||otherAmount>0){
                unappropriated.add(i,map);
            }else {
                i--;
            }


            if (receivedFlag){

                //记录完成标记
                item.addApportionAmount(waitAppropriatedAmount);
                item.setApportionComplete(true);
                //分摊完成
                if (unappropriatedAmount==0)return;
                //如果到账不够分摊完成则添加进待分摊明细
                if (!(amount>0||otherAmount>0))unappropriated.add(getUnappropriatedMapper(lossReceivedApportion));
            }else {
                //记录已分摊金额
                item.addApportionAmount(waitAppropriatedAmount+unappropriatedAmount);
                //到账金额分摊完成还有剩余则进入下一阶段分摊
            }

        }

    }

    public void appropriated(LossReceivedItem item, List<Map> unappropriated) {
        if (unappropriated == null || unappropriated.size() == 0 || item.isApportionComplete()) return;
        for (int i = 0; i < unappropriated.size(); i++) {
            Map map = unappropriated.get(i);
            //可分摊金额
            double waitAppropriatedAmount = item.getReceivedAmount() - item.getApportionAmount();
            if (waitAppropriatedAmount==0)return;
            Double amount = 0.0D;
            Double otherAmount = (Double) map.get("privateAmount");
            //门店私户摊现金
            amount = (Double) map.get("privateAmount")+(Double) map.get("amount");
            if (amount<=0)continue;
            LossReceivedApportion lossReceivedApportion = new LossReceivedApportion();
            lossReceivedApportion.setApportionOrder((String) map.get("id"));
            lossReceivedApportion.setApportionOrderType((String) map.get("type"));
            lossReceivedApportion.setReceivedDate((Date) map.get("date"));
            //未分摊金额-可分摊金额 >0则未到账 <0则全部到账
            double unappropriatedAmount = amount - waitAppropriatedAmount;
            //分摊完标记 true 不可 false 可
            boolean receivedFlag = unappropriatedAmount >= 0;
            lossReceivedApportion.setUnappropriatedAmount(receivedFlag ? unappropriatedAmount : 0);
            lossReceivedApportion.setApportionAmount(amount - lossReceivedApportion.getUnappropriatedAmount());
            lossReceivedApportion.setNeedApportionAmount(amount);
            lossReceivedApportion.setLossQuotationId(item.getLossQuotation().getId());
            lossReceivedApportion.setLossReceivedItem(item);
            amount-=lossReceivedApportion.getApportionAmount();
            if (amount<otherAmount){
                amount=0D;
                otherAmount=amount;
            }else {
                amount-=otherAmount;
            }
            //找到原先未分摊完成的改为分摊完成
            updateResoure(map);
            //清除待分摊记录
            lossReceivedApportion.setPrivateAccountAmount(0);
            map.put("privateAmount",otherAmount);
            map.put("amount",amount);
            lossReceivedApportion = create(lossReceivedApportion);
            unappropriated.remove(i);
            if (amount>0||otherAmount>0){
                unappropriated.add(i,map);
            }else {
                i--;
            }


            if (receivedFlag){

                //记录完成标记
                item.addApportionAmount(waitAppropriatedAmount);
                item.setApportionComplete(true);
                //分摊完成
                if (unappropriatedAmount==0)return;
                //如果到账不够分摊完成则添加进待分摊明细
                if (!(amount>0||otherAmount>0))unappropriated.add(getUnappropriatedMapper(lossReceivedApportion));
            }else {
                //记录已分摊金额
                item.addApportionAmount(waitAppropriatedAmount+unappropriatedAmount);
                //到账金额分摊完成还有剩余则进入下一阶段分摊
            }

        }

    }


    private void updateResoure(Map map) {
        List<LossReceivedApportion> lossReceivedApportions = lossReceivedApportionRepository.findAll(JpaDsl.toCriteria(
                "apportionOrder", "EQ", map.get("id"),
                "id", "NE", map.get("apportionId"),
                "type","EQ","RO",
                "unappropriatedAmount", "NE", 0));
        String apportionId = (String) map.get("apportionId");
        if (apportionId!=null)lossReceivedApportions.add(lossReceivedApportionRepository.findOne(apportionId));
        if (lossReceivedApportions.size()<=0)return;
        lossReceivedApportions.forEach(lossReceivedApportion -> {
            lossReceivedApportion.setUnappropriatedAmount(0);
            lossReceivedApportion.setPrivateAccountAmount(0);
            save(lossReceivedApportion);
            map.put("apportionsType",lossReceivedApportion.getType());
        });

    }

    public List<LossReceivedApportion> findAllDT(Map map){
        return lossReceivedApportionRepository.findAll(JpaDsl.toCriteria(
                "lossQuotationId", "EQ", map.get("id"),
                "type", "EQ", "DT"));
    }

    /**
     * 定损调整销售生成调整分摊明细
     * @param lossSaleAdjust
     * @return
     */
    public LossReceivedApportion lossSaleAdjustCreateLossApportion(LossSaleAdjust lossSaleAdjust) {
        if (lossSaleAdjust.getAdjustAmount()==0)return null;
        List<LossReceivedApportion> lossReceivedApportions = lossReceivedApportionRepository.findAll(JpaDsl.toCriteria("apportionOrder", "EQ", lossSaleAdjust.getRetailId()));
        double unappropriatedAmount = !lossReceivedApportions.isEmpty()?
                lossReceivedApportions.stream().mapToDouble(LossReceivedApportion::getUnappropriatedAmount).sum() :
                retailOrderRepository.findRetailOrder(lossSaleAdjust.getRetailId())
                        .getPaymentMethodSet()
                        .stream()
                        .filter(retailOrderPayMethod -> !retailOrderPayMethod.getPaymentMethodType().getId().equals("01"))
                        .mapToDouble(RetailOrderPayMethod::getAmount)
                        .sum();
        LossReceivedApportion lossReceivedApportion = new LossReceivedApportion();
        lossReceivedApportion.setApportionOrder(lossSaleAdjust.getRetailId());
        lossReceivedApportion.setApportionOrderType("RetailOrder");
        lossReceivedApportion.setAdjustmentAmount(lossSaleAdjust.getAdjustAmount());
        lossReceivedApportion.setNeedApportionAmount(lossSaleAdjust.getAdjustAmount());
        lossReceivedApportion.setUnappropriatedAmount(lossSaleAdjust.getAdjustAmount()+unappropriatedAmount);
        lossReceivedApportion.setType("DT");
        lossReceivedApportion.setLossQuotationId(lossSaleAdjust.getLossQuotationId());
        lossReceivedApportion.setReceivedDate(new Date());
        lossReceivedApportion.setRemark(lossSaleAdjust.getId()+",定损调整金额"+lossSaleAdjust.getAdjustAmount()+",定损调整日期:"+ DateUtil.format(new Date(),DateUtil.SHOW_DATE_FORMAT));
        return create(lossReceivedApportion);
    }

    private void createToPrepare(LossReceivedApportion lossReceivedApportion){
        LossReceivedItem lossReceivedItem = lossReceivedApportion.getLossReceivedItem();
        if (lossReceivedItem ==null)return;
        LossQuotation lossQuotation = lossReceivedItem.getLossQuotation();
        Enumeration accountType = lossReceivedItem.getAccountType();
        if (accountType ==null||!"002033".equals(accountType.getId()))return;

        Map data = mapper("amount", lossReceivedApportion.getApportionAmount(),
                "payment_type","002037",
                "deptId",lossQuotation.getFixedLossDept().getId(),
                "lossReceivedItemId",lossReceivedApportion.getId(),
                "lossQuotationId", lossQuotation.getId()
        );
        Object invoke = this.invoke("to.prepare.privateHomesAndSave", data);


    }

    /**
     * 缴款
     * @param request
     */
    public void prepare(SimpleRequest request){
        JSONArray jo = request.getJA();
        jo.forEach(o -> {
            JSONObject jsonObject = (JSONObject) o;
            //改为分摊明细编码
            String lossReceivedItemId = jsonObject.getString("lossReceivedItemId");
            double amount = jsonObject.getDoubleValue("amount");
            LossReceivedApportion lossReceivedApportion = lossReceivedApportionRepository.findOne(lossReceivedItemId);
            lossReceivedApportion.addPaymentAmount(amount);
            save(lossReceivedApportion);
            LossReceivedItem lossReceivedItem = lossReceivedApportion.getLossReceivedItem();
            if (lossReceivedItem !=null){
                lossReceivedItem.addToPrepareAmount(amount);
                SpringManager.getBean(LossReceivedItemRepository.class).saveAndFlush(lossReceivedItem);
            }
        });

    }
}
